#include "pch.h"
#include "Engine.h"
#include "DesktopFrameWin.h"

const int kTestSharedMemoryId = 123;

class FakeSharedMemory : public SharedMemory {
public:
	FakeSharedMemory(char* buffer, size_t size)
		: SharedMemory(buffer, size, 0, kTestSharedMemoryId), buffer_(buffer) {}
	~FakeSharedMemory() override { delete[] buffer_; }

private:
	char* buffer_;
	FakeSharedMemory(const FakeSharedMemory&) = delete;
	FakeSharedMemory& operator=(const FakeSharedMemory&) = delete;
};

class FakeSharedMemoryFactory : public SharedMemoryFactory {
public:
	FakeSharedMemoryFactory() {}
	~FakeSharedMemoryFactory() override {}

	std::unique_ptr<SharedMemory> CreateSharedMemory(size_t size) override {
		char*  data = new char[size];
		memset(data, 0, size);
		return std::unique_ptr<SharedMemory>(
			new FakeSharedMemory(data, size));
	}

private:
	FakeSharedMemoryFactory(const FakeSharedMemoryFactory&) = delete;
	FakeSharedMemoryFactory& operator=(const FakeSharedMemoryFactory&) = delete;
};

Engine::Engine(){
}

Engine::~Engine(){
}


int Engine::Init(){
	DesktopCaptureOptions options;
	dcw_ = std::make_unique<DesktopCapturerWin>(options);

	DesktopCapturerWin::SourceList sourceList;

	dcw_->GetSourceList(&sourceList);

	DesktopCapturerWin::SourceId sourceId;
	for (auto& source : sourceList)
	{
		sourceId = source.id;
	}

	if (!dcw_->SelectSource(sourceId))
	{
		return -1;
	}

	dcw_->Start(this);
	dcw_->SetSharedMemoryFactory(
		std::unique_ptr<SharedMemoryFactory>(new FakeSharedMemoryFactory()));
	return 0;
}

int Engine::Start(){
	if (running_)return 0;

	running_ = true;

	thread_ = std::make_unique<std::thread>(&Engine::run, this);

	return 0;
}

void Engine::Wait() {
	thread_->join();
}

void Engine::run() {
	while (running_) {
		if (maxFrame_ == 0)break;
		if (maxFrame_ > 0)maxFrame_ = maxFrame_ - 1;
		dcw_->CaptureFrame();
		std::this_thread::sleep_for(std::chrono::milliseconds(1000/fps_));
	}
	running_ = false;
}

int Engine::Stop(){
	running_ = false;
	if (thread_->joinable()) {

		thread_->join();
	}

	return 0;
}

void Engine::OnCaptureResult(DesktopCapturer::Result result,
	std::unique_ptr<DesktopFrame> frame) {
	if (result == DesktopCapturer::Result::SUCCESS && cb_ && cb_->video_cb) {

		sbeidc_frame newFrame;
		newFrame.data = frame->data();;
		newFrame.width = frame->size().width();
		newFrame.height = frame->size().height();
		newFrame.size = newFrame.width * newFrame.height * 4;
		cb_->video_cb(&newFrame);
	}
	else if (result == DesktopCapturer::Result::ERROR_PERMANENT) {
		running_ = false;
	}
}
